home *** CD-ROM | disk | FTP | other *** search
- From pgoujard@infocom.co.uk Wed Aug 11 23:30:51 1993
- Path: uunet!wupost!howland.reston.ans.net!agate!doc.ic.ac.uk!uknet!infocom.co.uk!pgoujard
- From: pgoujard@infocom.co.uk (Philippe Goujard)
- Newsgroups: alt.sources
- Subject: SLNR v1.2.c an offline newsreader 1/3
- Summary: Sources of the packet creator and offline newsreader
- Keywords: usenet offline newsreader
- Message-ID: <21528@infocom.co.uk>
- Date: 12 Aug 93 00:20:08 GMT
- Followup-To: alt.usenet.offline-reader
- Organization: INFOCOM Public Access Unix, (ModemLine) +44 [0] 734 340055
- Lines: 2225
- X-Newsreader: TIN [version 1.1 PL9]
- Xref: uunet alt.sources:9100
-
- Archive-name: slnr_12c
- Submitted-by: pgoujard@infocom.co.uk
-
-
- The SLNR package is an off-line usenet news reader : it is intended for users
- who want to connect to a host, download a packet with new messages, read
- them on their home machine and upload the replies later.
-
- Slnr stands for "Simple Local News Reader"
-
- The slnr package contains the following files
-
- - getnews.c : This program runs on your unix machine and get all unread
- articles in all subscribed newsgroups as well as your new mail and creates a
- packet (.zip, .arc, .zoo) that you can download and view with slnr.
-
- - slnr.c : The offline news reader which runs on your local machine and let
- you view and reply to messages. So far there is a Unix, Dos and Atari
- version.
-
- - postreply.c : Like getnews this program runs on unix machine and post mail
- and news articles from the reply packet.
-
- - colour.h : needed in slnr.c
-
- - sig.txt : optional signature to be appended at the end of your messages
-
- - slnp.fmt : The packet format
-
- - slnr.doc : First try at a documentation
-
-
- ============================================================================
-
- #!/bin/sh
- # This is a shell archive (shar 3.47)
- # made 08/11/1993 20:01 UTC by ppg@ozz
- # Source directory /big/ppg/News/unix/src/slnr
- #
- # existing files will NOT be overwritten unless -c is specified
- #
- # This is part 1 of a multipart archive
- # do not concatenate these parts, unpack them in order with /bin/sh
- #
- # This shar contains:
- # length mode name
- # ------ ---------- ------------------------------------------
- # 283 -r--r----- slnr/vcslnr
- # 25 -r--r----- slnr/slnr.ver
- # 4233 -r--r----- slnr/README
- # 594 -r--r----- slnr/colour.h
- # 24574 -r--r----- slnr/getnews.c
- # 4409 -r--r----- slnr/postreply.c
- # 51 -r--r----- slnr/sig.txt
- # 28248 -r--r----- slnr/slnp.fmt
- # 39079 -r--r----- slnr/slnr.c
- # 17155 -r--r----- slnr/slnr.doc
- # 273 -r--r----- slnr/slnr.ini
- # 8581 -r--r----- slnr/getnews.doc
- # 2093 -rw-rw---- slnr/a
- #
- if test -r _shar_seq_.tmp; then
- echo 'Must unpack archives in sequence!'
- echo Please unpack part `cat _shar_seq_.tmp` next
- exit 1
- fi
- # ============= slnr/vcslnr ==============
- if test ! -d 'slnr'; then
- echo 'x - creating directory slnr'
- mkdir 'slnr'
- fi
- if test -f 'slnr/vcslnr' -a X"$1" != X"-c"; then
- echo 'x - skipping slnr/vcslnr (File already exists)'
- rm -f _shar_wnt_.tmp
- else
- > _shar_wnt_.tmp
- echo 'x - extracting slnr/vcslnr (Text)'
- sed 's/^X//' << 'SHAR_EOF' > 'slnr/vcslnr' &&
- Module README version 1.6
- Module colour.h version 1.1
- Module getnews.c version 1.7
- Module postreply.c version 1.3
- Module sig.txt version 1.1
- Module slnp.fmt version 1.1
- Module slnr.c version 2.11
- Module slnr.doc version 1.4
- Module slnr.ini version 1.1
- Module getnews.doc version 1.5
- SHAR_EOF
- chmod 0440 slnr/vcslnr ||
- echo 'restore of slnr/vcslnr failed'
- Wc_c="`wc -c < 'slnr/vcslnr'`"
- test 283 -eq "$Wc_c" ||
- echo 'slnr/vcslnr: original size 283, current size' "$Wc_c"
- rm -f _shar_wnt_.tmp
- fi
- # ============= slnr/slnr.ver ==============
- if test -f 'slnr/slnr.ver' -a X"$1" != X"-c"; then
- echo 'x - skipping slnr/slnr.ver (File already exists)'
- rm -f _shar_wnt_.tmp
- else
- > _shar_wnt_.tmp
- echo 'x - extracting slnr/slnr.ver (Text)'
- sed 's/^X//' << 'SHAR_EOF' > 'slnr/slnr.ver' &&
- Project slnr version 1.1
- SHAR_EOF
- chmod 0440 slnr/slnr.ver ||
- echo 'restore of slnr/slnr.ver failed'
- Wc_c="`wc -c < 'slnr/slnr.ver'`"
- test 25 -eq "$Wc_c" ||
- echo 'slnr/slnr.ver: original size 25, current size' "$Wc_c"
- rm -f _shar_wnt_.tmp
- fi
- # ============= slnr/README ==============
- if test -f 'slnr/README' -a X"$1" != X"-c"; then
- echo 'x - skipping slnr/README (File already exists)'
- rm -f _shar_wnt_.tmp
- else
- > _shar_wnt_.tmp
- echo 'x - extracting slnr/README (Text)'
- sed 's/^X//' << 'SHAR_EOF' > 'slnr/README' &&
- README FILE
- Version : 1.6
- X
- What is SLNR ?
- ~~~~~~~~~~~~~~
- The SLNR package is an off-line usenet news reader : it is intended for users
- who want to connect to a host, download a packet with new messages, read
- them on their home machine and upload the replies later.
- X
- Slnr stands for "Simple Local News Reader"
- X
- The slnr package contains the following files
- X
- - getnews.c : This program runs on your unix machine and get all unread
- articles in all subscribed newsgroups as well as your new mail and creates a
- packet (.zip, .arc, .zoo) that you can download and view with slnr.
- X
- - slnr.c : The offline news reader which runs on your local machine and let
- you view and reply to messages. So far there is a Unix, Dos and Atari
- version.
- X
- - postreply.c : Like getnews this program runs on unix machine and post mail
- and news articles from the reply packet.
- X
- - colour.h : needed in slnr.c
- X
- - sig.txt : optional signature to be appended at the end of your messages
- X
- - slnp.fmt : The packet format
- X
- - slnr.doc : First try at a documentation
- X
- X
- What are my objectives ?
- ~~~~~~~~~~~~~~~~~~~~~~~~
- X - The specification for the format and the sources of getnews and slnr
- X will be widely available and in the public domain. (unlike QWK where the
- X format is cryptic).
- X
- X - There wont be any restriction for people who want to make shareware or
- X commercial version of the software.
- X
- X - There will be a "version" scheme : The packet format should stay the
- X same but even if it has to be altered the version will be noted in the
- X packet so future readers can extract information properly.
- X
- X - Development on multiple platforms will be encouraged (specially Mac and
- X Amigas where I don't have access). However I will keep the master source
- X and will decide how to integrate the updates and bug fixes I receive.
- X
- X - I will also encourage translations of the doc and the user interface (I
- X can work on the french version though :-) ).
- X
- X
- Where to go from there ?
- ~~~~~~~~~~~~~~~~~~~~~~~~
- X
- X - Compile and test the product on your machine (you don't really need a
- X makefile but feel free to write one if it helps).
- X
- X On the unix machine : compile getnews.c and postreply.c. You may have to
- X modify them for your system. Read the getnews.doc documentation and
- X create a .getnewsrc config file to suit your needs.
- X
- X On the dos/atari/etc... machine : Compile slnr.c, maybe create a "batch"
- X program to extract the files from the packet.
- X
- X - Send comments or bug report to me <pgoujard@infocom.co.uk>
- X
- X - If you are interested in SLNR and other off-line news reader,
- X read the usenet newsgroup : alt.usenet.offline-reader
- X
- X
- Changes since the previous issues
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- X
- - 23/05/93 : Start of slnr v2.0. Adding "#ifdef __STDC__" to cope with non
- ansi compilers.
- X
- - SLNR : Fixing the mail/posting bug: creation of a special area
- RMAIL.MSG which contains all replies by mail.
- X
- - SLNR : Accepting files which are at the mail or MMDF format.
- X
- - SLNR : Add the "LINES" entry in the config file (however on a dos machine
- it does not put the machine in that line mode, it just tells SLNR that
- there are more lines to use).
- X
- - SLNR : Change the #ifdef DOS to #ifdef __MSDOS__
- X
- - Getnews : Print a "." only every 10 articles.
- X
- - Getnews : If Delete_mailbox is unset, save the content of the mailbox to
- the $HOME/.oldmail file
- X
- - Getnews : Fix a bug that was allowing to close stderr.
- X
- - Getnews : Change the way the compression utility is used. The config file
- has to have an entry called "compress=" pointing to the program doing the
- compression and packing. By default /usr/local/bin/zip is used.
- X
- - Getnews : Add support for a configuration file + creation of getnews.doc
- X
- - SLNR : support the "quote" entry in the config file
- X
- - SLNR : Allow header editing for replies.
- X
- - SLNR : Add the "so.and.so wrote:" line in top of follow-ups
- X
- - SLNR : Add 's' and 'S' command to save an article to a file
- X
- - SLNR : Add '!' command to execute a shell program.
- X
- Thanks to
- ~~~~~~~~~
- X - Bob Rusbasan <rrusbassa@nyx.cs.du.edu> for carrying on intensive
- X tests on the dos version of SLNR and for his overall support.
- X
- X - Dick Grady <grady@world.std.com> for helping with getnews.c
- SHAR_EOF
- chmod 0440 slnr/README ||
- echo 'restore of slnr/README failed'
- Wc_c="`wc -c < 'slnr/README'`"
- test 4233 -eq "$Wc_c" ||
- echo 'slnr/README: original size 4233, current size' "$Wc_c"
- rm -f _shar_wnt_.tmp
- fi
- # ============= slnr/colour.h ==============
- if test -f 'slnr/colour.h' -a X"$1" != X"-c"; then
- echo 'x - skipping slnr/colour.h (File already exists)'
- rm -f _shar_wnt_.tmp
- else
- > _shar_wnt_.tmp
- echo 'x - extracting slnr/colour.h (Text)'
- sed 's/^X//' << 'SHAR_EOF' > 'slnr/colour.h' &&
- /*
- ** Module : colour.h
- ** Author : P.Goujard
- ** Started : 22/01/93
- ** Version : 1.1
- ** Last modified : 23 May 1993
- */
- #ifndef ATARI
- #define HOME "[H" /* home the cursor */
- #define CLS "[2J" /* clear the screen */
- #endif
- X
- #define BLACK 0
- #define RED 1
- #define GREEN 2
- #define YELLOW 3
- #define BLUE 4
- #define MAGENTA 5
- #define CYAN 6
- #define WHITE 7
- #define NONE 8
- #define MAX_CLR 20
- X
- #define RESET 0
- #define HIGH 1
- #define BLINK 5
- X
- X
- #define COL_HEAD "["
- X
- char *scr(int attribute,int foreground, int background);
- SHAR_EOF
- chmod 0440 slnr/colour.h ||
- echo 'restore of slnr/colour.h failed'
- Wc_c="`wc -c < 'slnr/colour.h'`"
- test 594 -eq "$Wc_c" ||
- echo 'slnr/colour.h: original size 594, current size' "$Wc_c"
- rm -f _shar_wnt_.tmp
- fi
- # ============= slnr/getnews.c ==============
- if test -f 'slnr/getnews.c' -a X"$1" != X"-c"; then
- echo 'x - skipping slnr/getnews.c (File already exists)'
- rm -f _shar_wnt_.tmp
- else
- > _shar_wnt_.tmp
- echo 'x - extracting slnr/getnews.c (Text)'
- sed 's/^X//' << 'SHAR_EOF' > 'slnr/getnews.c' &&
- /*
- ** Project : Simple Local News Reader
- **
- ** Name : GETNEWS
- ** Version : 1.7
- **
- ** Author : P.Goujard
- ** Started : 22/01/93
- ** Last modified : 11 Aug 1993
- ** Goal : Getting unread Mail and News articles from the spool
- ** directory and putting them in a SLNP file
- */
- X
- #include <stdio.h>
- #include <string.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <time.h>
- #include <unistd.h>
- #include <ctype.h>
- #include <stdlib.h>
- #include <dirent.h>
- X
- #define UNSET 0
- #define SET 1
- #define ASK 2
- X
- /* Values returned by lfgets() */
- #define LFGETS_OK 0
- #define LFGETS_EOF 1
- #define LFGETS_ERR 2
- X
- X
- #ifdef INFOCOM
- #include "new.h"
- #endif
- X
- /*
- ** Change those values to the one in your system
- */
- X
- /*
- ** Usually on unix a user has a file called ".newsrc" in his home
- ** directory.
- ** This file is created by newsreaders like, rn,nn,vn,tin,tass,trn
- ** and contains the list of newsgroups and last read pointers
- */
- #define NEWSRC ".newsrc"
- X
- /*
- ** nrc2 is the name of the temporary .newsrc
- ** You shouldn't need to change it
- */
- #define NRC2 "nrc2"
- X
- /*
- ** LOGDIR is the directory where error and log files are created
- ** Usually /tmp or /usr/tmp
- */
- #ifdef INFOCOM
- #define LOGDIR "/server/logfiles"
- #else
- #define LOGDIR "/usr/tmp"
- #endif
- #define LOGFILE "getnews.log"
- X
- /*
- ** Under MMDF, a mailbox consists of messages separated by 4 Ctrl A
- ** Normal mailboxes just use the "From " line as separator
- */
- #define MMDF_SEPARATOR ""
- X
- /*
- ** SPOOL is the directory where the news are located
- ** This has no effect with NNTP
- ** GROUPS is the file containing the description of each newsgroup
- */
- #define SPOOL "/usr/spool/news"
- #define GROUPS "/usr/lib/news/newsgroups"
- X
- /*
- ** The following names are consistent with the
- ** SLNP & Helldiver packet format.
- ** You shouldn't need to change them.
- ** For more info report to the file slnp.fmt
- */
- #define NEWSTXT ".MSG"
- #define AREALIST "AREAS"
- X
- /*
- ** PACKETNAME is used to define the first part of the name of the packet
- ** the extension is taken fron the compression used
- */
- #define PACKETNAME "SLNP"
- X
- X
- /* Prototypes */
- X
- #ifdef __STDC__
- X
- unsigned long add_file(char *f1,char *f2, int headermode);
- char *get_description(char *group,char *text);
- void dot2slash(char *line);
- int is_unread(int message_no,char *list_read,int last);
- int get_token(char *line,char **tlist,char **pos);
- char *upperit(char *line);
- int su_get( char *line, char *pos);
- int sua_get(char *line, char *pos);
- void index_message(int area,char *message,unsigned long offset);
- int exp_env(char *s);
- int lfgets(char **s, int *ns, FILE *stream);
- X
- #else
- X
- unsigned long add_file();
- char *get_description();
- void dot2slash();
- int is_unread();
- int get_token();
- char *upperit();
- int su_get();
- int sua_get();
- void index_message();
- int exp_env();
- int lfgets();
- X
- #define remove unlink
- X
- #endif
- void read_config();
- X
- /*
- ** Global variables
- */
- int Msgmax,Grpmax,Mmdf,Usenet_only,
- X Mail_only,Delete_mailbox,Get_mail,Mark_read,Do_index,Index_only;
- char Compress[80],Packet_name[80],Work_dir[80],Arctype[10];
- X
- int main (int argc, char *argv[])
- {
- X FILE *rc,*rc2,*log,*areas,*mbox,*fw;
- X char home[80],newsrc[80],nrc2[80], templine[255], slog[80];
- X char *nrcline, *list_read;
- X char newsgroup[80],*pos,newsdir[80],ngrp2[80],message[80];
- X char mlist_f[80],mailbox[80];
- X char mailbox_type,area_name[80];
- X int current_area=1, nowrite=0;
- X int i,last,message_cnt;
- X int total_msg=0,message_no;
- X int biggest;
- X int nrcsize = 256, retv;
- X struct dirent *ficdir;
- X DIR *rep;
- X unsigned long offset=0;
- #ifdef INFOCOM
- X struct user User;
- X
- X strcpy (User.login,getenv("LOGNAME"));
- X if (testuser(&User,USERBASE) > 0)
- X {
- X if ((show_priv_no(3,&User)==0) || show_flag_no(13,&User))
- X {
- X /* Not a gold user or has the no getnews flag */
- X fprintf (stderr,"Sorry, you are not allowed to use getnews\n");
- X return (-1);
- X }
- X }
- #endif
- X
- X if ((pos=getenv("HOME"))==NULL)
- X {
- X fprintf (stderr,"$HOME not defined\n");
- X return(-1);
- X }
- X strcpy (home,pos);
- X
- X read_config();
- X
- X if ((argc>1) && (strcmp(argv[1],"-i")==0))
- X Index_only=SET;
- X
- X if (Index_only==SET)
- X Do_index=SET;
- X
- X if (Mmdf==SET)
- X mailbox_type='M';
- X else
- X mailbox_type='m';
- X
- X if (Compress[0]=='\0') /* unset */
- X {
- X strcpy(Compress,"/usr/local/bin/zip");
- X fprintf(stderr,"WARNING: undefined compression utility, using %s\n",
- X Compress);
- X }
- X /*
- X Opening of Files
- X */
- X
- X /* remove the AREAS file */
- X sprintf (templine,"%s/%s",Work_dir,AREALIST);
- X remove(templine);
- X
- X sprintf (newsrc,"%s/%s",home,NEWSRC);
- X sprintf (nrc2,"%s/%s",Work_dir,NRC2);
- X
- X if((rc=fopen(newsrc,"r"))==NULL)
- X {
- X fprintf (stderr,"File [%s] not found\n",newsrc);
- X return(1);
- X }
- X
- X sprintf (slog,"%s/%s",LOGDIR,LOGFILE);
- X log=fopen (slog,"a");
- X if (log==NULL)
- X log=stderr;
- X
- X sprintf (mlist_f,"%s/%s",Work_dir,AREALIST);
- X if ((areas=fopen(mlist_f,"w"))==NULL)
- X {
- X fprintf (stderr,"Unable to create [%s] file \n",mlist_f);
- X return(1);
- X }
- X
- X
- X /*
- X ** Create the name of the first area
- X */
- X sprintf (area_name,"%s/%.3d%s",Work_dir,current_area,NEWSTXT);
- X remove( area_name ); /* just in case */
- X
- X /*
- X ** Processing Mail
- X */
- X message_cnt=0;
- X
- X if((Get_mail==ASK) && (Index_only==UNSET))
- X {
- X printf("Do you want to save your mail (y/N) ? ");
- X fflush(stdout);
- X fgets(templine,80,stdin);
- X if ((templine[0]=='y') || (templine[0]=='Y'))
- X Get_mail=SET;
- X }
- X
- X if((Get_mail==SET) && (Index_only==UNSET))
- X {
- X if ((pos=getenv("MAIL"))==NULL)
- X {
- X fprintf(stderr,"Error: $MAIL not defined\n");
- X return(1);
- X }
- X strcpy (mailbox,pos);
- X if ((mbox=fopen(mailbox,"r"))!=NULL)
- X {
- X fclose(mbox);
- X add_file(area_name,mailbox,0); /* No rnews header */
- X
- X /*
- X ** Update the AREAS file
- X ** This version does not create an index file
- X */
- X fprintf (areas,"001\tPrivate Mail\t%cn\n",mailbox_type);
- X message_cnt=0;
- X
- X if (Delete_mailbox==UNSET)
- X {
- X /* Move the mailbox to the .oldmail file */
- X sprintf(templine,"%s/.oldmail",home);
- X add_file(templine,mailbox,0);
- X printf("Your mailbox has been appended to file %s\n",templine);
- X }
- X /* Create an empty mailbox */
- X remove(mailbox);
- X fw=fopen(mailbox,"w");
- X fclose(fw);
- X
- X current_area++;
- X sprintf (area_name,"%s/%.3d%s",Work_dir,current_area,NEWSTXT);
- X remove( area_name ); /* just in case */
- X }
- X }
- X
- X /*
- X ** Processing News
- X */
- X if (Mark_read==ASK)
- X {
- X printf("Do you want to mark saved articles as read (y/N) ? ");
- X fflush(stdout);
- X fgets (templine,80,stdin);
- X if ((templine[0]=='y') || (templine[0]=='Y'))
- X Mark_read=SET;
- X }
- X
- X if (Mark_read==SET)
- X {
- X /* Create a backup .newsrc */
- X sprintf( templine,"%s/%s.bak", home, NEWSRC);
- X remove( templine );
- X
- X add_file( templine, newsrc, 0 );
- X
- X /* We create the new .newsrc */
- X if((rc2=fopen(nrc2,"w"))==NULL)
- X {
- X fprintf (stderr,"Unable to create [%s] file\n",nrc2);
- X return(1);
- X }
- X }
- X
- X /*
- X ** Main Loop
- X */
- X
- X /*
- X ** For each line in the .newsrc
- X */
- X while( (retv=lfgets(&nrcline,&nrcsize,rc)) == LFGETS_OK )
- X {
- X if (Grpmax && (current_area > Grpmax))
- X {
- X if( !nowrite ) /* Prints only the msg once */
- X printf("\nMaximum number of groups reached (%d)\n",Grpmax);
- X nowrite = 1;
- X }
- X
- X /*
- X ** Selects only the subscribed newsgroups
- X */
- X if (!nowrite && (pos=strchr(nrcline,':'))!=NULL)
- X {
- X if (nrcline[strlen(nrcline)-1]=='\n')
- X nrcline[strlen(nrcline)-1]='\0';
- X
- X offset = 0;
- X message_cnt=0; /* reset the message counter */
- X i=0;
- X while (nrcline[i]!=':')
- X {
- X newsgroup[i]=nrcline[i];
- X i++;
- X }
- X newsgroup[i]='\0';
- X
- X /*
- X ** Save the list of read articles and
- X ** Get the number of the last one
- X ** the newsrc line looks like :
- X ** groupname: value-value,...,value
- X */
- X pos++;
- X while(*pos==' ') /* Skip the space(s) */
- X pos++;
- X /*
- X ** pos points to either the first character of the article list,
- X ** or to the \0 string terminator.
- X */
- X list_read = pos;
- X
- X pos=nrcline+strlen(nrcline)-1; /* Points to the latest char */
- X while (isdigit(*pos))
- X pos--;
- X pos++; /* Skip the - , or : character */
- X last=atoi(pos);
- X biggest=last;
- X
- X strcpy (ngrp2,newsgroup);
- X dot2slash(newsgroup);
- X sprintf (newsdir,"%s/%s",SPOOL,newsgroup);
- X if (chdir(newsdir)) /* directory doesnt exist */
- X {
- X /*
- X ** This newsgroup does not exist any more
- X ** It may be a good idea to remove it from the .newsrc
- X */
- X fprintf (log,"%s : unknown\n",ngrp2);
- X }
- X else
- X {
- X /*
- X ** Look for unread file
- X */
- X if ((rep=opendir(newsdir))==NULL)
- X fprintf (log,"DIR : %s not readable\n",newsdir);
- X else while ((ficdir=readdir(rep))!=NULL)
- X {
- X sprintf (message,"%s/%s",newsdir,ficdir->d_name);
- X message_no = atoi(ficdir->d_name);
- X
- X
- X if (message_no && is_unread(message_no,list_read,last))
- X {
- X /*
- X ** We have found a new article.
- X ** Look if it's number is bigger than the biggest
- X */
- X if (Msgmax && (total_msg >=Msgmax))
- X {
- X if( !nowrite )
- X printf("\nMaximum number of messages reached (%d)\n",Msgmax);
- X nowrite = 1;
- X }
- X
- X if( !nowrite )
- X {
- X if (message_no > biggest)
- X biggest=message_no;
- X message_cnt++;
- X total_msg++;
- X /* Only display the group if there are messages */
- X if (message_cnt==1)
- X printf ("\n%s:",ngrp2);
- X
- X if ((message_cnt%10)==0)
- X {
- X printf ("."); /* show the message progression */
- X fflush(stdout);
- X }
- X /*
- X ** Add the message to the temporary file
- X ** Or create the index
- X */
- X if (Do_index==SET)
- X index_message(current_area,message,offset);
- X if (Index_only==UNSET)
- X offset += add_file (area_name,message,1);
- X
- X }
- X }
- X }
- X closedir(rep);
- X if (message_cnt)
- X {
- X /*
- X ** Write an entry in the AREAS list file
- X */
- X if(get_description(ngrp2,templine)==NULL)
- X strcpy (templine,"Unknown");
- X fprintf (areas,"%.3d\t%s\tu%c\t%s\t%d\n",current_area,
- X ngrp2,
- X (Do_index==SET) ? 'c' : 'n',
- X templine,message_cnt);
- X current_area++;
- X sprintf (area_name,"%s/%.3d%s",
- X Work_dir,current_area,NEWSTXT);
- X remove( area_name ); /* Just in case */
- X }
- X if (Mark_read==SET)
- X {
- X fprintf (rc2,"%s: 1-%d\n",ngrp2,biggest);
- X }
- X }
- X }
- X else if (Mark_read==SET)
- X {
- X /* Just copy the line as it is */
- X fprintf(rc2,"%s",nrcline);
- X }
- X }
- X if(retv == LFGETS_ERR)
- X {
- X fprintf(stderr,
- X "\nWarning - Malloc failure while processing file %s\n", NEWSRC );
- X exit(1);
- X }
- X
- group_done:
- X fclose(rc);
- X if (Mark_read==SET)
- X {
- X fclose(rc2);
- X rc=fopen(newsrc,"w");
- X if (rc!=NULL)
- X {
- X /*
- X ** Rewrites the .newsrc
- X */
- X printf ("\nRewriting .newsrc\n");
- X rc2=fopen(nrc2,"r");
- X while(fgets(nrcline,160,rc2)!=NULL)
- X fprintf(rc,"%s",nrcline);
- X fclose(rc2);
- X fclose(rc);
- X remove(nrc2);
- X }
- X else
- X fprintf (log,"%s : Unable to rewrite .newsrc \n",getenv("LOGNAME"));
- X }
- X
- X if (log != stderr)
- X fclose (log);
- X fclose (areas);
- X printf ("\n%d messages processed\n",total_msg);
- X
- X /*
- X ** Now compress the work files
- X */
- X chdir(Work_dir);
- X
- X /*
- X ** Check that the compress program exists
- X ** and that we can create the packet file
- X */
- X sprintf(templine,"%s.%s",Packet_name,Arctype);
- X if (((fw=fopen(Compress,"r"))==NULL)||
- X ((rc=fopen(templine,"w"))==NULL))
- X fprintf(stderr,"Unable to compress *.MSG and AREAS files\n");
- X else
- X {
- X fclose(fw);
- X fclose(rc);
- X remove(templine);
- X
- X sprintf (templine,"%s %s.%s *.MSG *.IDX %s",
- X Compress,Packet_name,Arctype,AREALIST);
- X
- X if(system(templine))
- X fprintf(stderr,"Compress program returned an error, work files not removed\
- n");
- X else
- X {
- X sprintf (templine,"rm *.MSG *.IDX");
- X system(templine);
- X remove(AREALIST);
- X }
- X printf ("\nFile %s.%s has been created\n",Packet_name,Arctype);
- X }
- X return (0); /* Normal End */
- }
- X
- void dot2slash(line)
- char *line;
- {
- X if (line==NULL)
- X return;
- X while (*line)
- X {
- X if (*line=='.')
- X *line='/';
- X line++;
- X }
- }
- X
- /*
- ** add_file(f1,f2) append file f2 behind file f1
- ** and return the number of bytes written
- */
- unsigned long add_file (f1,f2,headermode)
- char *f1,*f2;
- int headermode;
- {
- X char header[80];
- X FILE *df1,*df2;
- X int c;
- X unsigned long length;
- X struct stat buf;
- X
- X if ( ((df1=fopen(f1,"a"))==NULL) || ((df2=fopen(f2,"r"))==NULL) )
- X {
- X fprintf (stderr,"Unable to open a file [%s] or [%s]!\n",f1,f2);
- X return (0);
- X }
- X
- X if (headermode)
- X {
- X /* Adding a "#! rnews xxxx" line as header */
- X stat(f2,&buf);
- X length=(unsigned long)buf.st_size;
- X sprintf (header,"#! rnews %ld\n",length);
- X length += strlen(header);
- X fprintf (df1,"%s",header);
- X }
- X
- X while ((c=fgetc(df2))!=EOF)
- X fputc(c,df1);
- X
- X fclose(df1);
- X fclose(df2);
- X return(length);
- }
- X
- /*
- ** Get the descrition of the newsgroup
- ** or return a null pointer if it cannot be found
- */
- char *get_description(group,text)
- char *group;
- char *text;
- {
- X char line[255],*pos;
- X int n=strlen(group);
- X FILE *fr;
- X if ((fr=fopen(GROUPS,"r"))==NULL)
- X return(NULL);
- X while (fgets(line,255,fr)!=NULL)
- X {
- X line[strlen(line)-1]='\0';
- X if (strncmp(line,group,n)==0)
- X {
- X pos=line+n; /* Points to the tab */
- X if ((*pos=='\0')||(*(pos+1)=='\0'))
- X return(NULL);
- X while ((*pos=='\t')||(*pos==' '))
- X pos++;
- X strcpy (text,pos);
- X return(text);
- X }
- X }
- X fclose( fr );
- X return(NULL);
- }
- X
- /*
- ** Return 1 if the article of number message_no is either greater than the
- ** last read or not in the list of read articles
- */
- #ifdef __STDC__
- int is_unread(int message_no, char *list_read, int last)
- #else
- int is_unread(message_no,list_read,last)
- int message_no,last;
- char *list_read;
- #endif
- {
- X int begin,end,value;
- X char orig, *pos1, *pos;
- X if ((message_no > last) || (list_read[0]=='\0'))
- X return(1);
- X
- X pos=list_read;
- X orig = 0;
- X
- X while (*pos) {
- X /* Read the first number */
- X pos1=pos;
- X while (isdigit(*pos))
- X pos++;
- X switch(*pos) {
- X case ',': /* A single number */
- X case '\0': /* End of string */
- X orig = *pos;
- X value=atoi(pos1);
- X if (message_no == value)
- X return(0); /* This article has been read */
- X if (message_no < value)
- X return(1); /* Lower than the lowest read */
- X break;
- X
- X case '-': /* A range */
- X begin = atoi(pos1);
- X if (message_no == begin)
- X return(0); /* This article has been read */
- X if (message_no < begin)
- X return(1); /* Lower than the lowest read */
- X /* Read the second number */
- X pos++;
- X pos1=pos;
- X while(isdigit(*pos))
- X pos++;
- X orig = *pos;
- X end = atoi(pos1);
- X if (message_no < begin)
- X return(1);
- X if (message_no <= end)
- X return(0);
- X break;
- X
- X
- X default : /* Unknown char */
- X orig='1';
- X fprintf(stderr,"Warning, char <%c> unrecognised in .newsrc\n",*pos);
- X break;
- X }
- X if (orig)
- X pos++;
- X }
- X return(1); /* Unread */
- }
- X
- X
- char *upperit(line)
- char *line;
- {
- X char *pos=line;
- X while (*pos)
- X {
- X *pos=toupper(*pos);
- X pos++;
- X }
- X return (line);
- }
- X
- X
- /*
- ** Get a token from the token list out of the line
- ** update pos as the position in the line after the token
- ** and return the token number if found, -1 else.
- */
- #ifdef __STDC__
- int get_token(char *line,char **tlist,char **pos)
- #else
- int get_token(line,tlist,pos)
- char *line, **tlist,**pos;
- #endif
- {
- X int i=0,l,ll;
- X char *c;
- X
- X /* search for the "=" separator */
- X c=strchr(line,'=');
- X if (c==NULL)
- X return (-1);
- X ll=c-line; /* Get line length */
- X *c='\0';
- X /* *pos points to the first non blank character after the = */
- X *pos=c+1;
- X while ((**pos==' ')||(**pos=='\t'))
- X *pos += 1;
- X upperit(line);
- X while (tlist[i][0])
- X {
- X l=strlen(tlist[i]);
- X if((l==ll) && (strcmp(line,tlist[i])==0))
- X return(i);
- X i++;
- X }
- X return(-1); /* failure */
- }
- X
- /*
- ** Open the .getnewsrc file and read the config
- */
- void read_config()
- {
- X FILE *fr;
- X int n;
- X char line[80],old_line[80],*pos,rcfile[80];
- X static char *tlist[15]={
- X "MSGMAX",
- X "GRPMAX",
- X "MMDF",
- X "USENET_ONLY",
- X "MAIL_ONLY",
- X "DELETE_MAILBOX",
- X "GET_MAIL",
- X "MARK_READ",
- X "COMPRESS",
- X "PACKET_NAME",
- X "WORK_DIR",
- X "ARCTYPE",
- X "DO_INDEX",
- X "INDEX_ONLY",
- X ""};
- X
- X
- X /* Default */
- X
- X /*
- X ** The maximum number of articles and of newsgroups
- X ** If UNSET, no limit
- X */
- X
- X Grpmax = Msgmax = UNSET;
- X
- X /*
- X ** The following fields accept values SET and UNSET
- X */
- X Mmdf = Usenet_only = Mail_only = Delete_mailbox = Index_only = UNSET;
- X Do_index = SET;
- X
- X /*
- X ** The following field accept values SET, UNSET and ASK
- X */
- X Get_mail = Mark_read = ASK;
- X
- X Compress[0]='\0';
- X strcpy(Arctype,"zip");
- X strcpy(Packet_name,"INFONEWS");
- X sprintf(Work_dir,"%s/News",getenv("HOME"));
- X
- X sprintf(rcfile,"%s/.getnewsrc",getenv("HOME"));
- X if ((fr=fopen(rcfile,"r"))==NULL)
- X return; /* No config file, use default values */
- X
- X while( fgets( line, 80, fr ) != NULL )
- X {
- X strcpy( old_line, line );
- X
- X /* Ignore comments and blank lines */
- X if( line[0] != '#' && line[0] != '\n' )
- X {
- X if (line[strlen(line)-1]=='\n') /* Remove end CR */
- X line[strlen(line)-1]='\0';
- X
- X switch (get_token(line,tlist,&pos))
- X {
- X case 0: /* msgmax */
- X Msgmax = atoi(pos);
- X break;
- X
- X case 1: /* grpmax */
- X Grpmax = atoi(pos);
- X break;
- X
- X case 2: /* mmdf */
- X if( (n = su_get( old_line, pos )) != -1 )
- X Mmdf = n;
- X break;
- X
- X case 3: /* Usenet Only */
- X if( (n = su_get( old_line, pos )) != -1 )
- X Usenet_only = n;
- X break;
- X
- X case 4: /* Mail Only */
- X if( (n = su_get( old_line, pos )) != -1 )
- X Mail_only = n;
- X break;
- X
- X case 5: /* Delete Mailbox */
- X if( (n = sua_get( old_line, pos )) != -1 )
- X Delete_mailbox = n;
- X break;
- X
- X case 6: /* Get Mail */
- X if( (n = sua_get( old_line, pos )) != -1 )
- X Get_mail = n;
- X break;
- X
- X case 7: /* Mark Read */
- X if( (n = sua_get( old_line, pos )) != -1 )
- X Mark_read = n;
- X break;
- X
- X case 8: /* Compress */
- X exp_env( strcpy(Compress,pos) );
- X break;
- X
- X case 9: /* Packet Name */
- X exp_env( strcpy(Packet_name,pos) );
- X break;
- X
- X case 10: /* Work dir */
- X exp_env( strcpy(Work_dir,pos) );
- X break;
- X
- X case 11: /* Arc type */
- X exp_env( strcpy(Arctype,pos) );
- X break;
- X
- X case 12: /* Get index */
- X if( (n = su_get( old_line, pos )) != -1 )
- X Do_index = n;
- X break;
- X
- X case 13: /* Get index */
- X if( (n = su_get( old_line, pos )) != -1 )
- X Index_only = n;
- X break;
- X
- X default:
- X fprintf(stderr,"Line <%s> has no known keyword\n",old_line);
- X break;
- X }
- X }
- X }
- X fclose(fr);
- }
- X
- int su_get(line,pos)
- char *line;
- char *pos;
- {
- X switch( *pos )
- X {
- X case 'Y':
- X case 'y':
- X case 'S':
- X case 's':
- X return(SET);
- X
- X case 'N':
- X case 'n':
- X case 'U':
- X case 'u':
- X return(UNSET);
- X
- X default:
- X fprintf(stderr, "Error in config file: Line <%s> ",line);
- X fprintf(stderr, "should be either SET or UNSET\n");
- X break;
- X }
- X return( -1 );
- }
- X
- int sua_get(line,pos)
- char *line;
- char *pos;
- {
- X switch( *pos )
- X {
- X case 'Y':
- X case 'y':
- X case 'S':
- X case 's':
- X return(SET);
- X
- X case 'N':
- X case 'n':
- X case 'U':
- X case 'u':
- X return(UNSET);
- X
- X case 'A':
- X case 'a':
- X return(ASK);
- X
- X default:
- X fprintf(stderr, "Error in config file: Line <%s> ",line);
- X fprintf(stderr, "should be either SET, UNSET, or ASK\n");
- X break;
- X }
- X return( -1 );
- }
- X
- void index_message(area,message,offset)
- int area;
- char *message;
- unsigned long offset;
- {
- X char From[80],Subject[80],Date[80],temp[80],line[512],Ref[80],Id[80],*pos;
- X int bytes=0,line_no=0,headermode=1;
- X FILE *fr,*fw;
- X struct stat buf;
- X
- X From[0] = Subject[0] = Date[0] = Ref[0] = '\0';
- X
- X sprintf(temp,"%s/%.3d.IDX",Work_dir,area);
- X
- X if ( ((fw=fopen(temp,"a"))==NULL) || ((fr=fopen(message,"r"))==NULL) )
- X {
- X fprintf (stderr,"Unable to open a file [%s] or [%s]!\n",temp,message);
- X return;
- X }
- X
- X /* Adding a the size of "#! rnews xxxx" line to the offset */
- X stat( message, &buf );
- X sprintf( temp, "#! rnews %ld\n", (unsigned long)buf.st_size);
- X offset += strlen( temp );
- X
- X /* Find the last part of the path for the mesg Id */
- X pos=strrchr(message,'/');
- X if (pos==NULL)
- X strcpy(Id,message);
- X else
- X strcpy(Id,pos+1);
- X
- X while(fgets(line,512,fr)!=NULL)
- X {
- X line[511]='\0'; /* Just in case */
- X if (line[strlen(line)-1]=='\n')
- X line[strlen(line)-1]='\0';
- X if (headermode)
- X {
- X if (line[0]=='\0')
- X headermode=0;
- X else
- X {
- X if (strncmp(line,"From: ",6)==0)
- X strcpy(From,line+6);
- X else if (strncmp(line,"Subject: ",9)==0)
- X strcpy(Subject,line+9);
- X else if (strncmp(line,"Date: ",6)==0)
- X strcpy(Date,line+6);
- X else if (strncmp(line,"References: ",12)==0)
- X strcpy(Ref,line+12);
- X }
- X }
- X else
- X line_no++;
- X bytes += strlen(line);
- X }
- X fprintf(fw,"%ld\t%s\t%s\t%s\t%s\t%s\t%d\t%d\n",offset,
- X Subject,From,Date,Id,Ref,bytes,line_no);
- X fclose(fr);
- X fclose(fw);
- }
- X
- /*
- ** exp_env()
- **
- ** Expand any environment variables in input string.
- ** Put result back into input string.
- ** Input string must be big enough to hold the expanded expression.
- **
- ** Returns 0 (FALSE) if any specified environment variables are not defined;
- ** Else returns 1 (TRUE).
- */
- #ifdef __STDC__
- int exp_env(char *s)
- #else
- int exp_env(s)
- char *s;
- #endif
- {
- X char *in, *out, *cptr, *env_val;
- X int c, cv, ret_val;
- X char env_name[30];
- X char *temp;
- X
- X if(strchr(s,'$') == NULL)
- X return(1);
- X
- X temp = (char *)malloc((unsigned)(strlen(s)+1));
- X if(temp == NULL)
- X {
- X fprintf(stderr, "Error - function exp_env: Malloc failed.\n");
- X return(0);
- X }
- X
- X strcpy(temp,s);
- X in = temp;
- X out = s;
- X ret_val = 1;
- X
- X while( c=*in++)
- X { /* While thare are characters */
- X if(c != '$')
- X {
- X /* regular part of string */
- X *out++ = (char)c;
- X }
- X else
- X {
- X /* Beginning of environment variable */
- X /* Pick off the name of environment variable */
- X cptr = env_name;
- X while( (c=*in++) && ( isalnum(c) || c == '_') )
- X *cptr++ = (char)c;
- X *cptr = '\0';
- X in--;
- X /* Get value */
- X env_val = getenv(env_name);
- X if(env_val == NULL)
- X ret_val = 0;
- X else
- X {
- X /* copy value into output string */
- X cptr = env_val;
- X while(cv=*cptr++)
- X *out++ = (char)cv;
- X }
- X if(c == '\0') break; /* End of input string */
- X }
- X }
- X
- X *out = '\0'; /* Terminate resulting string. */
- X
- X free((char *)temp); /* Release malloced space */
- X
- X return(ret_val);
- }
- X
- /*
- ** Function:
- **
- ** int lfgets(char *s, int *ns, FILE *stream)
- **
- ** Gets an arbitrarily-long line from an input stream. The terminating
- ** newline is returned also.
- **
- ** If s is NULL, then lfgets uses malloc() to get storage space of size ns
- ** or larger to hold the input line. A pointer to the newly-malloced
- ** space is returned in parameter s.
- ** If s is not NULL, it must be a pointer obtained from a malloc-like
- ** function (malloc, calloc, realloc, etc.).
- **
- ** Lfgets starts filling s with the input line.
- ** If the line is longer than s, then lfgets uses realloc() as necessary
- ** to get a large enough storage space. In this case, pointer s is changed
- ** to point to the (possibly-relocated) new storage area,
- ** and ns will change to reflect the new size of the storage space.
- **
- ** If all goes well, lfgets returns LFGETS_OK.
- ** If the first character read is an end-of-file, lfgets returns LFGETS_EOF.
- ** If malloc() or realloc() fail, then lfgets LFGETS_ERR.
- */
- X
- #ifdef __STDC__
- int lfgets(char **s, int *ns, FILE *stream)
- #else
- int lfgets(s, ns, stream)
- char **s;
- int *ns;
- FILE *stream;
- #endif
- {
- X int c, i;
- X int maxch;
- X
- X if(*s == NULL) {
- X /* malloc some space to start with */
- X *ns = 256;
- X *s = (char *)malloc((unsigned)*ns);
- X if(*s == (char *)NULL)
- X return(LFGETS_ERR);
- X }
- X
- X i = 0;
- X
- X while(1) {
- X maxch = *ns - 1; /* maximum # of characters to read into array,
- X not counting the terminating null. */
- X
- X
- X /* Read data, putting it into s. */
- X for(; i < maxch; i++) {
- X c = fgetc(stream);
- X
- X if(c == EOF) {
- X if(i == 0)
- X /* EOF at first attempt to read */
- X return(LFGETS_EOF);
- X else {
- X /* last line of file had no \n terminator. */
- X (*s)[i+1] = '\0'; /* terminate string. */
- X return(LFGETS_OK);
- X }
- X }
- X
- X (*s)[i] = (char)c;
- X if(c == '\n') {
- X /* we have found the end of the input line */
- X (*s)[++i] = '\0'; /* terminate string. */
- X return(LFGETS_OK);
- X }
- X }
- X
- X /* There is more of the line yet to read */
- X /* Get more storage space. */
- X *ns += 256;
- X *s = (char *)realloc(*s, (unsigned)*ns);
- X if(*s == (char *)NULL)
- X return(LFGETS_ERR);
- X
- X /* And, repeat. */
- X }
- X
- }
- X
- SHAR_EOF
- chmod 0440 slnr/getnews.c ||
- echo 'restore of slnr/getnews.c failed'
- Wc_c="`wc -c < 'slnr/getnews.c'`"
- test 24574 -eq "$Wc_c" ||
- echo 'slnr/getnews.c: original size 24574, current size' "$Wc_c"
- rm -f _shar_wnt_.tmp
- fi
- # ============= slnr/postreply.c ==============
- if test -f 'slnr/postreply.c' -a X"$1" != X"-c"; then
- echo 'x - skipping slnr/postreply.c (File already exists)'
- rm -f _shar_wnt_.tmp
- else
- > _shar_wnt_.tmp
- echo 'x - extracting slnr/postreply.c (Text)'
- sed 's/^X//' << 'SHAR_EOF' > 'slnr/postreply.c' &&
- /*
- ** Postreply.c : Posting mail and messages from SLNP reply packet
- ** Author : Philippe Goujard
- ** Started : 08/04/93
- ** Version : 1.3
- */
- X
- #include <stdio.h>
- #include <string.h>
- /* Post article with partial header */
- #define INEWSCMD "/usr/lib/news/inews -h"
- #define MAILCMD "/usr/ucblib/sendmail -t < "
- #define TMP "/usr/tmp"
- #define MMDF_SEPARATOR ""
- #define MAIL_SEPARATOR "From "
- X
- union converter
- {
- X unsigned long l;
- X unsigned char c[4];
- } Conv;
- X
- int is_big_endian()
- {
- X char testline[80];
- X
- X Conv.l=16909060; /* Should be 01 02 03 04 */
- X sprintf( testline, "%d%d%d%d",Conv.c[0],Conv.c[1],Conv.c[2],Conv.c[3]);
- X if( strcmp( testline, "1234" ) == 0 )
- X return( 1 ); /* true */
- X return( 0 );
- }
- X
- void post_new_articles(msg_file, encoding, program )
- char *msg_file, *program;
- char encoding;
- {
- X FILE *fr,*fw;
- X char c, *ptr, line[255],line2[255], tmpname[80];
- X
- X if ((fr=fopen(msg_file,"r"))==NULL)
- X return; /* No article to post */
- X
- X sprintf(tmpname,"%s/art.%d",TMP,getpid());
- X if ((fw=fopen(tmpname,"w"))==NULL)
- X {
- X fclose(fr);
- X return;
- X }
- X switch( encoding )
- X {
- X case 'm': /* Mail format */
- X fgets(line,255,fr); /* Get the From line */
- X fprintf(fw,"%s",line);
- X
- X while (fgets(line,255,fr)!=NULL)
- X {
- X if ( strncmp( line, "From ", 5)==0)
- X {
- X /* Process the article */
- X fclose(fw);
- X sprintf( line2, "%s %s", program, tmpname);
- X system( line2 );
- X fw=fopen(tmpname,"w"); /* Create a new tmp file for next article */
- X fprintf(fw,"%s",line);
- X }
- X else
- X fprintf(fw,"%s",line);
- X }
- X /* Process the last article */
- X fclose(fw);
- X sprintf (line,"%s %s",program,tmpname);
- X system(line);
- X break;
- X
- X case 'M': /* MMDF format */
- X fgets(line,255,fr); /* Get the CtrlAs line */
- X
- X while (fgets(line,255,fr)!=NULL)
- X {
- X if ( strncmp( line, MMDF_SEPARATOR, 4)==0)
- X {
- X /* Process the article */
- X fclose(fw);
- X sprintf( line2, "%s %s", program, tmpname);
- X system( line2 );
- X fw=fopen(tmpname,"w"); /* Create a new tmp file for next article */
- X fgets(line,255,fr); /* Get the CtrlAs line */
- X }
- X else
- X fprintf(fw,"%s",line);
- X }
- X fclose(fw);
- X break;
- X
- X case 'u':
- X /* Get the rnews line */
- X fgets(line,255,fr);
- X
- X while (fgets(line,255,fr)!=NULL)
- X {
- X if (strncmp(line,"#! rnews ",9)==0)
- X {
- X /* Process the article */
- X fclose(fw);
- X sprintf (line,"%s %s",program,tmpname);
- X system(line);
- X fw=fopen(tmpname,"w"); /* Create a new tmp file for next article */
- X }
- X else
- X fprintf(fw,"%s",line);
- X }
- X /* Process the last article */
- X fclose(fw);
- X sprintf (line,"%s %s",program,tmpname);
- X system(line);
- X break;
- X
- X case 'b':
- X case 'B':
- X while( (c=fgetc( fr )) != EOF )
- X {
- X if( is_big_endian() ) /* Sparc and 68k processors */
- X {
- X Conv.c[0] = c;
- X Conv.c[1] = fgetc(fr);
- X Conv.c[2] = fgetc(fr);
- X Conv.c[3] = fgetc(fr);
- X }
- X else /* Intel processors */
- X {
- X Conv.c[3] = c;
- X Conv.c[2] = fgetc(fr);
- X Conv.c[1] = fgetc(fr);
- X Conv.c[0] = fgetc(fr);
- X }
- X /* Allocate memory */
- X if( ( ptr = (char *)malloc( Conv.l * sizeof( char * ) ) ) == NULL )
- X {
- X fclose( fr );
- X fclose( fw );
- X remove(tmpname);
- X return;
- X }
- X
- X fread( ptr, 1, Conv.l, fr );
- X fwrite( ptr, 1, Conv.l, fw );
- X /* Process the article */
- X fclose(fw);
- X sprintf (line,"%s %s",program,tmpname);
- X system(line);
- X fw=fopen(tmpname,"w"); /* Create a new tmp file for next article */
- X free( ptr );
- X }
- X fclose(fw);
- X break;
- X
- X }
- X fclose(fr);
- X /* remove(tmpname); */
- }
- X
- main()
- {
- X FILE *fr;
- X int ln=0;
- X char line[80],*p,message[20],program[80];
- X
- X if ((fr=fopen("REPLIES","r"))==NULL)
- X {
- X fprintf(stderr,"Nothing to post\n");
- X return;
- X }
- X while(fgets(line,80,fr)!=NULL)
- X {
- X ln++;
- X if ((p=strchr(line,'\t'))==NULL)
- X {
- X fprintf(stderr,"Error in REPLIES, no prefix in line %d\n",ln);
- X return;
- X }
- X *p='\0';
- X sprintf(message,"%s.MSG",line);
- X strcpy(line,p+1);
- X if ((p=strchr(line,'\t'))==NULL)
- X {
- X fprintf(stderr,"Error in REPLIES no reply kind in line %d\n",ln);
- X return;
- X }
- X *p='\0';
- X p++; /* Get the encoding type */
- X if (strcmp(line,"mail")==0)
- X strcpy( program, MAILCMD );
- X else if (strcmp(line,"news")==0)
- X strcpy( program, INEWSCMD );
- X else
- X {
- X fprintf(stderr,"Error : reply kind invalid in line %d\n",ln);
- X return;
- X }
- X post_new_articles(message, *p, program);
- X }
- X fclose(fr);
- }
- SHAR_EOF
- chmod 0440 slnr/postreply.c ||
- echo 'restore of slnr/postreply.c failed'
- Wc_c="`wc -c < 'slnr/postreply.c'`"
- test 4409 -eq "$Wc_c" ||
- echo 'slnr/postreply.c: original size 4409, current size' "$Wc_c"
- rm -f _shar_wnt_.tmp
- fi
- # ============= slnr/sig.txt ==============
- if test -f 'slnr/sig.txt' -a X"$1" != X"-c"; then
- echo 'x - skipping slnr/sig.txt (File already exists)'
- rm -f _shar_wnt_.tmp
- else
- > _shar_wnt_.tmp
- echo 'x - extracting slnr/sig.txt (Text)'
- sed 's/^X//' << 'SHAR_EOF' > 'slnr/sig.txt' &&
- The one and only usenet god : Email god@heaven.com
- SHAR_EOF
- chmod 0440 slnr/sig.txt ||
- echo 'restore of slnr/sig.txt failed'
- Wc_c="`wc -c < 'slnr/sig.txt'`"
- test 51 -eq "$Wc_c" ||
- echo 'slnr/sig.txt: original size 51, current size' "$Wc_c"
- rm -f _shar_wnt_.tmp
- fi
- # ============= slnr/slnp.fmt ==============
- if test -f 'slnr/slnp.fmt' -a X"$1" != X"-c"; then
- echo 'x - skipping slnr/slnp.fmt (File already exists)'
- rm -f _shar_wnt_.tmp
- else
- > _shar_wnt_.tmp
- echo 'x - extracting slnr/slnp.fmt (Text)'
- sed 's/^X//' << 'SHAR_EOF' > 'slnr/slnp.fmt' &&
- X
- X SLNP file format
- X ~~~~~~~~~~~~~~~~
- X
- Author : Philippe Goujard (author of SLNR)
- X
- Date : 24 Apr 1993
- X
- Version : 1.1 Draft
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X
- Mail me at <pgoujard@infocom.co.uk> for the latest version of this format
- X
- The author of this original document may be contacted via e-mail at
- rhys@cs.uq.oz.au.
- X
- X
- X
- X
- X
- 0. Document Control
- ===================
- X
- 0.1 Contents List
- ~~~~~~~~~~~~~~~~~
- X
- <To be provided >
- X
- X
- 0.2 Document Cross Reference
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- X
- [1] : RFC 822, Standard for the format of Arpa Internet text messages (1982)
- X
- [2] : RFC 1036
- X
- [3] : RFC 1341
- X
- [4] : The Helldiver Packet Format version 1.1 by Rhys Weatherley.
- X
- X
- 0.3 Copyright notice :
- ~~~~~~~~~~~~~~~~~~~~~~
- This document is in the public domain : you can copy it, use it to make
- off-line readers or on-line "doors" on bbs and servers and even make money
- out of it. The ONLY restriction being that when you copy or distribute that
- document you copy this notice so other people will have the same rights
- as you.
- X
- [4] is Copyright (c) 1992 Rhys Weatherley
- X
- 0.4 Changes Forecast
- ~~~~~~~~~~~~~~~~~~~~
- X
- - The COMMAND file will have to be defined, and specially what command are
- allowed.
- X
- - Optionals files and fields can become mandatory in future versions.
- X
- X
- 0.5 Changes from the previous issue
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- X
- Almost everything.
- SLNP Version 1.0 was a beta release and was intended to change after receiving
- the comments from testers.
- This version is mostly equivalent to [4].
- X
- Main changes with SLNP v1.0 are:
- X
- X - The file names have changed and the text of the newsgroups are now
- X splitted into different files.
- X
- X - There are new files to Index and display Info
- X
- X - The field separator is no longer a ":" but a Tabulation
- X
- X - The format of the messages include a "#! rnews size" line at the top
- X of each message but no longer include the "***[END]***" as message
- X separator.
- X
- X
- X
- X
- 1. General
- ==========
- X
- X
- 1.1 Scope
- ~~~~~~~~~
- X
- This document provides a design for an off-line news readers packet format
- compatible with [4].
- X
- X
- 1.2) Introduction
- ~~~~~~~~~~~~~~~~~
- X
- For many years, the FidoNet community has been using QWK and other formats
- to enable users to download their mail and conferences to be read while
- off-line. This not only saves phone charges and prevents tying up BBS
- lines for long periods of time; it also allows a user to use much more
- powerful tools on their own machine to process the downloaded "packets"
- than what can be made available in an on-line environment.
- X
- To date however, very little work has been done in the USENET and dial-in
- Unix community to facilitate the same user operations. Some attempts have
- been made to use QWK, but due to QWK's limitations and unsuitability for
- the USENET message formats, such efforts have not been very successful.
- X
- Within USENET, the tendency seems to be either "dial-in to some other
- machine and put up with it", or "set up your own USENET site". The former
- keeps the user at the mercy of whatever user interfaces the admin of the
- other machine sees fit to install, and the latter requires far more
- computing knowledge than the average computer user is expected to have.
- Both of these can serve to lock out large portions of the computer-literate
- public from experiencing USENET. The latter option can also give rise to
- security problems in the form of forged USENET messages, which a more
- controlled dial-in system avoids.
- X
- The purpose of this document is to define a new packet format which is
- aware of the conventions used in the USENET community, forming a middle
- ground between dial-in user interfaces and full USENET connectivity. It is
- not limited to downloading USENET news however. The same format could be
- used to enable a Unix user to package up their Unix mailbox and download it
- for later perusal. The format is extensible to other kinds of news or
- conference systems, so it is feasible, although not yet defined, that QWK
- or FidoNet messages could be accomodated within the same packet as USENET
- messages.
- X
- X
- X
- 1.3) Vocabulary and naming convention
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- X - SLNR : Silly Little News Reader : One of the newsreaders that can read
- X SLNP packets.
- X
- X - SLNP : The packet file transmitted between the host and the home machine
- X However, by extension we often use "slnr" when refering to the packet.
- X This is improper : SLNR is ONE of the programs that can read SLNP packets
- X but it will not be the only one.
- X
- X - Message area : A public conference, known in the usenet community as
- X "newsgroup" and in the CompuServe community as "Forum".
- X
- X - Host or generating host : The machine on which the packet is created.
- X
- X - Receiving host or home machine : The machine on which the packet will
- X be read.
- X
- X - Packet Generator : The program, run on the host, which creates a packet
- X in the SLNP format.
- X
- X - Packet poster : Th program, run on the hosts, which extract the
- X replies from an uploaded packet and post them "to the network".
- X
- X SLNP is independant of a compression method (although most of the time
- X "zip" is used, it is possible to have packets created by "zoo", "arc", or
- X even simply "tar").
- X
- X SLNP is also independant of the packet name (which is often machine
- X dependant, like on dos you are limited to 8+3).
- X If possible the name should contain :
- X - The name of the server / BBS
- X - A sequence number or a date
- X - The packet type (SLNP)
- X - The compression or archive method used (.zip, .tar.Z etc...)
- X
- X From those 3 informations the most important is probably the compression
- X method, because :
- X - Downloaded packets can be put in different directories for different
- X servers / BBS
- X - The date of the packet can be infered from the date of download
- X - The packet type has been negociated before download and there are less
- X packets types than compression methods.
- X
- X
- X
- X
- X
- 2) Anatomy of a packet
- ======================
- X
- X
- 2.1) List of files
- ~~~~~~~~~~~~~~~~~~
- X
- The minimum requirement is a method to collect a group of files into a
- single packet, and a method to expand the packet back into the original
- files. Each of the filenames in a packet should be stored in upper case on
- those systems where case matters.
- X
- A packet consists of zero or more "message areas" (commonly called
- "newsgroups" in USENET jargon). Usually, each message area corresponds to
- a different topic of discussion.
- X
- The following file specifications may appear in a packet:
- X
- INFO : Optional textual information.
- LIST : Optional List of message areas on the generating system.
- AREAS : List of the message areas within the packet.
- REPLIES : Index of the reply message areas from the user.
- *.MSG : Text of the messages in a particular message area.
- *.IDX : Optional, Index information for messages in a message area.
- COMMAND : Optional, List of commands to be executed.
- X
- Other filenames may also appear in the packet, but are not defined by this
- specification, so they should be avoided by generating software, and ignored
- by receiving software.
- X
- The INFO file is an optional text file which may contain any kind of textual
- information from the generating system. Typically this file would only be
- present if there is some kind of urgent message that must be sent to the
- receiving user. Use of this file to store the name of the generating BBS
- and other such static information is possible, but discouraged to save space
- and transmission time. Lines in this text file are terminated by LF
- characters (not by CR-LF pairs).
- X
- The LIST file contains a list of all message areas that are available on
- the generating system, together with the format of the messages. This is
- an optional text file, with lines terminated by LF characters. This should
- only be sent to the receiving system upon user request. It is specified
- further in the section "LIST FILE".
- X
- The AREAS file contains an index of the message areas present within the
- packet, specifying the name of the message area, the filename the messages
- may be found in, and the message format. This is specified further in the
- next section.
- X
- The REPLIES file contains an index of the message areas present within the
- packet that contain reply messages from a user which should be mailed or
- posted on the receiving system (usually the system that packets are normally
- downloaded from for off-line reading). In most cases, a packet will contain
- either an AREAS file or a REPLIES file, but both may be present. See the
- section "REPLIES FILE" below for more information.
- X
- The *.MSG files contain the text of the messages from a single message area.
- The actual format of this file depends on the type of message area specified
- in the AREAS file. See the section "MESSAGE FILES" below for more information.
-
- X
- The *.IDX files provide an index into the *.MSG files, usually specifying
- where each message starts and the contents of some of the common message
- header fields. These files are intended for use by reading software on the
- recipient's system to quickly display an overview of the messages present in
- a message area. See the section "INDEX FILES" below for more information.
- X
- The COMMAND files is optional and contains the version information. If
- absent version 1.1 is assumed. In future releases it may contain commands
- to "subscribe" or "unsubscribe" to a message area.
- X
- X
- 2.2 The AREAS file
- ~~~~~~~~~~~~~~~~~~
- X
- The AREAS file is a text file containing zero or more lines, each of which
- specifies a single message area, its type and the name of the message/index
- file pair in which the messages appear.
- Lines are terminated with a single LF character (not CR-LF).
- X
- In particular, each line has the following form:
- X
- prefix<TAB>area name<TAB>type[<TAB>Optional fields]
- X
- Field : prefix
- Value : Name of the message / index file for this area
- Default : None, this field is mandatory
- Example : "042" or "UNIX".
- Comments: This name has to be kept short and without characters that may
- not be recognised by some file systems.
- X
- The message and index files corresponding to the message area have the names
- "prefix.MSG" and "prefix.IDX" respectively. If "prefix" contains alphabetic
- characters, they must be upper case.
- X
- X
- Field : Area name
- Value : Any sequence of printable ASCII characters (space through tilde).
- Default : None, this field is mandatory
- Example : "comp.lang.c" or "C langage conference".
- Comments: For usenet messages this will be the name of the newsgroup.
- X
- Although binary characters (ascii value > 127) are allowed, they can be used
- if the host and the home machine agree on a standard to represent them on
- the screen. This can be the case for example of accents or special
- characters for non-english langages.
- X
- The only hard rule is that the name may not contain TAB, CR or LF.
- Receiving software should treat the name as an indivisible string to be
- displayed to the user.
- X
- X
- Field : type
- Value : two chars (see below)
- Default : None, this field is mandatory
- Example : "un" "uC" "Mc" ...
- Comments: The first char describes the format of the message file (.MSG) and th
- esecond char the format of the index file (.IDX).
- X
- The following message file formats are currently defined (case is significant):
-
- X
- u : USENET news articles
- m : Unix mailbox articles
- M : Mailbox articles in the MMDF format
- b : Binary 8-bit clean mail format
- B : Binary 8-bit clean news format
- X
- The individual message file encodings are explained further in the next
- section. The following index file formats are currently defined (again, case
- is significant):
- X
- n : No index file
- c : C-news overview database format
- C : Shorter C-news overview database format
- i : Offset/length pairs delineating the messages
- X
- These types are explained further in the section "INDEX FILES" below.
- X
- The optional fields are:
- X
- Field : Description
- Value : Any sequence of printable ASCII characters (space through tilde).
- Default : A null string
- Example : "Telecommunications digest. (Moderated)"
- Comments: For usenet messages this is often found in the file
- /usr/lib/news/newsgroups.
- Like for the "area name" field, binary characters should only appear if the
- host and the home machine have agreed on a representation for them.
- X
- Field : Number of messages
- Value : A numeric ascii string
- Default : A null string
- Example : "123"
- Comments: This field can be used for example if no index file is given.
- X
- If an optional field is absent and it's follower is present then the <tab>
- delimiter shall be present. For example :
- X
- Field1<tab>Field2<tab><tab>Field4 is valid while
- Field1<tab>Field2<tab>Field4 is invalid
- X
- Note that : Field1<tab><tab><tab> is valid but not necessary.
- X
- Further types may be defined in future versions of this specification. If
- the receiving software does not recognise a message file type, it should ignore
-
- the corresponding message and index files. If the receiving software does
- not recognise a index file type, it can either ignore the message file, or
- attempt to break down the message file into separate messages by some other
- means. The user should be warned if a message area has been ignored.
- X
- It is recommended that packet generation software support at least the index
- file type 'C', since it gives the best compromise between transmission time
- and assisting the reader software to display message area summaries.
- X
- X
- A message area may appear more than once in the AREAS file, each time with a
- different prefix, but this is discouraged. This could be used to split large
- message areas across more than one message file, but this is more conveniently
- handled by generating a separate packet containing the area contination.
- X
- X
- X
- X
- 2.3 Message Files
- ~~~~~~~~~~~~~~~~~
- X
- The format of the message file depends on the message area type specified in
- the AREAS file. This version of the specification defines three formats,
- which are in common use in the USENET and Unix community, and two additional
- binary formats which permit messages to be stored with no modification or
- assumptions about line lengths and byte values.
- X
- For each of first three formats, lines are terminated with LF characters.
- Any CR characters in the messages should be considered as data characters, or
- ignored on receipt. In particular, MS-DOS systems should strip CR characters
- >from text messages before writing them to a packet.
- X
- A 'u' (USENET) message file is a text file consisting of one or more messages
- prefixed with an rnews header. This header has the form "#! rnews n" where
- "n" is the number of bytes in the message that follows the header, excluding
- the line-feed character which terminates the header. If the number in the
- header is followed by white space and other characters, these other characters
- should be ignored, until the terminating LF character is encountered.
- X
- A note about the rnews header: although a terser separator could be used, the
- rnews header has the following advantages: (a) the messages can be extracted
- in the absense of index files, or where the index files have an unknown type,
- and (b) the message files can be imported into a USENET system as standard
- rnews batches. Thus, if the user wishes to set up a real USENET site, or
- simply use dedicated USENET software to read packets, they can use their
- existing packet provider as a convenient read-only newsfeed, with no extra
- burden placed on the system administrator of the generating system.
- X
- A 'm' (Unix mailbox) message file is a text file consisting of one or more
- messages. The first line of each message must start with the character
- sequence "From ". Any remaining lines in the message which start with
- "From " should have the character '>' prepended. Thus the "From " lines
- delimit the message file into separate messages.
- X
- A 'M' (MMDF mailbox) message file is a sequence of one or more messages,
- separated by at least 4 Control-A characters. The message file may optionally
- start and end with a sequence of such characters. If a sequence of 4 or more
- Control-A characters occurs in a message, it should be "adjusted" by the
- insertion of spaces to split the sequence. The use of Control-A characters
- within a message is discouraged.
- X
- The 'm' and 'M' formats were chosen for mail because of their common
- occurrence in the Unix community. The generating system may elect to instead
- convert a mailbox into the USENET format if it wishes, and set the message area
-
- name to some descriptive string to inform the reader. It is recommended
- however, that 'm' or 'M' be used for mail and 'u' for USENET news so that
- reader software can make a distinction between the two if it wishes.
- X
- The 'b' (binary mail) and 'B' (binary news) formats are identical. The
- contents of each message must conform to RFC-822/1036 ([1]/[2]) and may
- contain content information compatible with RFC-1341 ([3]). The only
- difference between the messages of these formats and the preceding formats
- is that no assumption is made about line lengths, and any of the 256 values
- for a byte may be used in any position. Each message is preceded by a 4-
- byte value which indicates the length of the message in bytes, stored in
- big-endian order (i.e. high byte first, low byte last). The difference
- between 'b' and 'B' is a semantic one: message files of type 'b' are
- expected to contain mail messages, and message files of type 'B' are
- expected to contain news messages. Thus, reader software can make a
- distinction between the two if it desires.
- X
- For most practical purposes, 'u', 'm' and 'M' should be sufficient. The binary
-
- 'b' and 'B' types should be used for articles that contain 8-bit binary data.
- It is possible to use type 'u' for binary data as well, but 'm' and 'M'
- cannot be because the message contents may be modified. When MIME becomes
- more wide-spread, it is expected that binary messages containing programs,
- sound, pictures and video will become popular, necessitating these binary
- types.
- X
- Note that MIME messages can be stored in 'u', 'm' and 'M' message files, but
- any binary components should be encoded with quoted-printable or base64 (which
- is expected to be the most common usage of MIME in the near future). It is
- not required that 'b' or 'B' be used for MIME messages: only those containing
- raw unencoded binary data (as indicated by the Content-transfer-encoding
- header value "binary").
- X
- X
- X
- X
- 2.4) Index Files
- ~~~~~~~~~~~~~~~~
- X
- This specification defines four index file types, which provide varying
- degrees of support for packet readers.
- X
- Type 'n' indicates that no index file is present, and it is up to the packet
- reader to extract messages from the message file. Use of this type is
- discouraged, except where transmission time must be minimised (at the expense
- of packet reader simplicity). It may be useful where the generating system
- is providing a USENET newsfeed using packets.
- X
- A type 'c' index file is a text file (LF terminated lines), with one line per
- message that occurs in the message file. The lines in the index file should
- be in the same order as the corresponding messages. Each line has the
- following form:
- X
- offset<TAB>subject<TAB>author<TAB>date<TAB>mesgid<TAB>refs<TAB>bytes<TAB>lines
- X
- X
- offset : Seek position in the message file of where the corresponding
- message starts. The first seek position is 0. For the 'u'
- format, this indicates the start of the line following the
- rnews header line. For the 'm' format, this indicates the
- start of the "From " line and for the 'M' format, this
- indicates the start of the article after the Control-A
- sequence. For the 'b' and 'B' formats, this indicates the
- first byte of the message after the 4-byte message length.
- X
- subject : The "Subject:" line from the message.
- X
- author : The "From:" line from the message.
- X
- date : The "Date:" line from the message.
- X
- mesgid : The "Message-Id:" line from the message.
- X
- refs : The "References:" line from the message.
- X
- bytes : The number of bytes in the message.
- X
- lines : The "Lines:" line from the message. Note that this field
- is pretty useless these days on USENET, but is still popular.
- It is meant to indicate the number of lines in the body of
- the message. Generating software may elect to re-generate
- this value if it is not present in the original message,
- but this is not required.
- X
- If any of these fields contained TAB's, newlines or other white space in the
- SHAR_EOF
- true || echo 'restore of slnr/slnp.fmt failed'
- fi
- echo 'End of part 1'
- echo 'File slnr/slnp.fmt is continued in part 2'
- echo 2 > _shar_seq_.tmp
- exit 0
-
-
- --
- Philippe Goujard <Sysop> Email : pgoujard@infocom.co.uk
- INFOCOM : FREE (yes free!) Usenet access in the UK - (0734) 34 00 55
- For more information mail "info@infocom.co.uk" a daemon will autoreply
-
-